﻿using System;
using System.ComponentModel;
using System.Collections.Specialized;
using System.Threading;

namespace System.Collections.ObjectModel
{

    [Serializable]
    public class ReadOnlyObservableCollection<T> : ReadOnlyCollection<T>, INotifyCollectionChanged, INotifyPropertyChanged
    {
        // Fields
        [NonSerialized]
        private NotifyCollectionChangedEventHandler collectionChanged;

        [NonSerialized]
        private PropertyChangedEventHandler propertyChanged;

        // Events
        protected event NotifyCollectionChangedEventHandler CollectionChanged
        {
            add
            {
                NotifyCollectionChangedEventHandler handler2;
                NotifyCollectionChangedEventHandler collectionChanged = this.collectionChanged;
                do
                {
                    handler2 = collectionChanged;
                    NotifyCollectionChangedEventHandler handler3 = (NotifyCollectionChangedEventHandler)Delegate.Combine(handler2, value);
                    collectionChanged = Interlocked.CompareExchange<NotifyCollectionChangedEventHandler>(ref this.collectionChanged, handler3, handler2);
                }
                while (collectionChanged != handler2);
            }
            remove
            {
                NotifyCollectionChangedEventHandler handler2;
                NotifyCollectionChangedEventHandler collectionChanged = this.collectionChanged;
                do
                {
                    handler2 = collectionChanged;
                    NotifyCollectionChangedEventHandler handler3 = (NotifyCollectionChangedEventHandler)Delegate.Remove(handler2, value);
                    collectionChanged = Interlocked.CompareExchange<NotifyCollectionChangedEventHandler>(ref this.collectionChanged, handler3, handler2);
                }
                while (collectionChanged != handler2);
            }
        }

        protected event PropertyChangedEventHandler PropertyChanged
        {
            add
            {
                PropertyChangedEventHandler handler2;
                PropertyChangedEventHandler propertyChanged = this.propertyChanged;
                do
                {
                    handler2 = propertyChanged;
                    PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Combine(handler2, value);
                    propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
                }
                while (propertyChanged != handler2);
            }
            remove
            {
                PropertyChangedEventHandler handler2;
                PropertyChangedEventHandler propertyChanged = this.propertyChanged;
                do
                {
                    handler2 = propertyChanged;
                    PropertyChangedEventHandler handler3 = (PropertyChangedEventHandler)Delegate.Remove(handler2, value);
                    propertyChanged = Interlocked.CompareExchange<PropertyChangedEventHandler>(ref this.propertyChanged, handler3, handler2);
                }
                while (propertyChanged != handler2);
            }
        }

        event NotifyCollectionChangedEventHandler INotifyCollectionChanged.CollectionChanged
        {
            add
            {
                this.CollectionChanged += value;
            }
            remove
            {
                this.CollectionChanged -= value;
            }
        }

        event PropertyChangedEventHandler INotifyPropertyChanged.PropertyChanged
        {
            add
            {
                this.PropertyChanged += value;
            }
            remove
            {
                this.PropertyChanged -= value;
            }
        }

        // Methods
        public ReadOnlyObservableCollection(ObservableCollection<T> list)
            : base(list)
        {
            ((INotifyCollectionChanged)base.Items).CollectionChanged += new NotifyCollectionChangedEventHandler(this.HandleCollectionChanged);
            ((INotifyPropertyChanged)base.Items).PropertyChanged += new PropertyChangedEventHandler(this.HandlePropertyChanged);
        }

        private void HandleCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
        {
            this.OnCollectionChanged(e);
        }

        private void HandlePropertyChanged(object sender, PropertyChangedEventArgs e)
        {
            this.OnPropertyChanged(e);
        }

        protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs args)
        {
            if (this.collectionChanged != null)
            {
                this.collectionChanged(this, args);
            }
        }

        protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
        {
            if (this.propertyChanged != null)
            {
                this.propertyChanged(this, args);
            }
        }

    }

}